<script setup lang="ts">
import {NFlex,NButton,NIcon,
  NText,NDivider,NCard,
  NTag,NScrollbar,NDescriptions,
  NDescriptionsItem,NFormItem,NInputNumber,
  NCheckbox,NCheckboxGroup,NRadioGroup,NRadio
} from "naive-ui"
import {FileOpenSharp, SettingsSharp,ArrowBackSharp} from "@vicons/material"
import {useIPCInjectApi} from "../utils/ipcInjectApi";
import {computed, reactive, ref} from "vue";
import type {DetectedLog, LoadedData, PersonDetail, YoloLog} from "../../common/types";
import {Player,Video,Ui} from "@vime/vue-next";


const API = useIPCInjectApi();
const loadedData = ref<LoadedData>({
  videoPath:"",
  detectedLog:[],
  fps:25,
  size:[1920,1080]
})

const filterDetectedLogs = computed<DetectedLog[]>(() => {
  const childFilterRes = loadedData.value.detectedLog.map(log=>{
    let yoloLog:YoloLog[]=[];
    let person:PersonDetail[]=[];
    if(filter.value.only!="PERSON"){
      yoloLog = log.yoloLog.filter(item=>{
        return item.confidence>filter.value.yoloConfidenceThreshold && filter.value.yoloNeed.includes(item.name);
      })
    }
    if(filter.value.only!="YOLO"){
      person = log.personDetail.filter(item=>{
        let need = true
        if(filter.value.personSex != "DISABLE"&& item.sex!=filter.value.personSex){
          need = false
        }
        if(!filter.value.personAgeRange.includes(item.ageRange)){
          need = false
        }
        return need
      })
    }
    const detectedLog:DetectedLog = {
      timestamp: log.timestamp,
      yoloLog:yoloLog,
      personDetail:person,
    }
    return detectedLog;
  })
  return childFilterRes.filter((log)=>{
    return log.yoloLog.length > 0 || log.personDetail.length > 0;
  });
})

const yoloNeedOptions = computed<{label:string,value:string}[]>(()=>{
  const names:string[] = [];
  loadedData.value.detectedLog.forEach((log=>{
    log.yoloLog.forEach((item)=>{
      const name = item.name;
      names.indexOf(name)<0?names.push(name):null;
    })
  }));
  filter.value.yoloNeed=names;
  const options:{label:string,value:string}[] = names.map((item)=>{return {
    label:item,
    value:item,
  }})
  return options;
})

const filter = ref<{
  only:"YOLO"|"PERSON"|"DISABLE"
  yoloConfidenceThreshold:number
  yoloNeed:string[],
  personSex:"Male"|"Female"|"DISABLE"
  personAgeRange:("Age18-60"|"AgeOver60"|"AgeLess18")[]
}>({
  only:"DISABLE",
  yoloConfidenceThreshold:0,
  yoloNeed:[],
  personSex:"DISABLE",
  personAgeRange:["Age18-60","AgeOver60","AgeLess18"]
})

const loaded = ref<boolean>(false);

const tryLoad = ()=>{
  API.loadData().then(data=>{
    console.log(data);
    loadedData.value=data;

    loaded.value=true;
  })
}

const showtime =(timestamp:number)=>{
  const second = Math.trunc(timestamp/loadedData.value.fps);
  return `${Math.trunc(second/3600).toString().padStart(2,"0")}:${(Math.trunc(second/60)%60).toString().padStart(2,"0")}:${(second%60).toString().padStart(2,"0")}`;
}
const sumYoloRes = (yoloLog:YoloLog[])=>{
  const countRes:{[key:string]:number} = {}
  yoloLog.forEach((log:YoloLog)=>{
    if(Object.keys(countRes).indexOf(log.name)>=0){
      countRes[log.name]+=1
    }else{
      countRes[log.name]=1
    }
  })
  return countRes;
}
const nowDisplayFrame = ref<number>(-1);

const coverColor = (color:string) => {
  if(color=="red")return {color:"#d41807"};
  if(color=="grey")return {color:"#454545"};
  if(color=="brown")return {color:"#705721"};
  if(color=="blue")return {color:"#005aa7"};
  if(color=="white")return {color:"#ffffff"};
  if(color=="green")return {color:"#41d407"};
  return {color};
}
type VideoType = InstanceType<typeof Video>
const nowVideo = ref<VideoType>();
const videoHolder = ref<HTMLDivElement>();

const selectFrame = (data: DetectedLog)=>{
  nowDisplayFrame.value = data.timestamp;
  if (nowVideo.value){
    nowVideo.value.getAdapter().then(adapter=>{
      adapter.setCurrentTime(data.timestamp/loadedData.value.fps);
      adapter.pause();
      setOverlay(data);
    }).catch((err)=>console.log(err));
  }
}

const setOverlay = (data: DetectedLog)=>{
  const newOverlay:Border[]=[];
  data.yoloLog.forEach((log:YoloLog)=>{
    newOverlay.push({
      type:"YOLO",
      x1:log.box.x1,
      x2:log.box.x2,
      y1:log.box.y1,
      y2:log.box.y2,
      title:`yolo_${log.name}(${log.confidence.toFixed(2)})`
    })
  })
  data.personDetail.forEach((log:PersonDetail,index:number)=>{
    newOverlay.push({
      type:"PERSON",
      x1:log.box[0],
      x2:log.box[2],
      y1:log.box[1],
      y2:log.box[3],
      title:`person_${index+1}`
    })
  })
  overlay.value=newOverlay;
}

type Border = {
  type:"YOLO"|"PERSON"
  x1:number
  x2:number
  y1:number
  y2:number
  title:string;
}
const overlay = ref<Border[]>([]);


const computeBorderStyle = (border:Border)=>{
  const rate = videoHolder.value.clientWidth /loadedData.value.size[0];
  const left = border.x1 * rate;
  const top  = border.y1 * rate;
  const width = (border.x2 - border.x1) * rate;
  const height = (border.y2 - border.y1) * rate;
  return {
    top:`${top}px`,
    left:`${left}px`,
    width:`${width}px`,
    height:`${height}px`,
    border:"solid red 1px",
    position: "absolute"
  }
}
</script>

<template>
  <n-flex justify="space-between" style="margin: 10px">
    <div>
      <n-button text v-if="loaded" @click="loaded=false;overlay=[]">
        <template #icon>
          <arrow-back-sharp/>
        </template>
        返回
      </n-button>
    </div>
    <n-button>
      <template #icon>
        <n-icon>
          <settings-sharp/>
        </n-icon>
      </template>
      设置
    </n-button>
  </n-flex>
  <n-divider style="margin: 0" />
  <div style="width: 100%;height: calc(100vh - 55px)">
    <n-flex justify="center" vertical style="height: 100%" v-if="!loaded">
      <n-flex justify="center">
        <n-button size="large" type="success" @click="tryLoad">
          <template #icon>
            <n-icon>
              <file-open-sharp/>
            </n-icon>
          </template>
          选择视频
        </n-button>
      </n-flex>
      <n-flex justify="center">
        <div>
          <p>
            <n-text depth="3">
              请将脚本生成的json文件放置在同一文件夹内，识别结果会自动加载
            </n-text>
          </p>
          <p>
            <n-text depth="3">
              如 a.mp4文件，会自动加载a_*.json所有结果
            </n-text>
          </p>
        </div>
      </n-flex>
    </n-flex>
    <n-flex style="height: 100%;gap: 0" v-else>
      <div style="width: 60%" ref="videoHolder">
        <div style="width: 100%;position: relative">
          <Player controls :autoplay="false" @play="overlay=[]">
            <Video ref="nowVideo">
              <source
                  :src="'file://'+loadedData.videoPath"
                  :data-src="'file://'+loadedData.videoPath"
                  type="video/mp4"
              />
            </Video>
          </Player>
          <div
              v-for="border in overlay"
              :style="computeBorderStyle(border)"
          >
            <div v-if="border.type=='PERSON'" style="position:absolute;top:-35px;left: 0;border: none;font-size: 15px">
              {{border.title}}
            </div>
            <div v-else style="position:absolute;top:-20px;left: 0;border: none;font-size: 15px">
              {{border.title}}
            </div>
          </div>
        </div>
        <n-text style="margin: 10px;font-size: 24px">过滤器</n-text>
        <n-flex style="gap: 0">
          <div style="width: calc(50% - 1px)">
            <n-flex style="margin: 5px 10px">
              <n-button
                  size="small"
                  :type="filter.only=='YOLO'?'error':'default'"
                  @click="filter.only=='YOLO'?filter.only='DISABLE':filter.only='YOLO'"
              >
                {{filter.only=='YOLO'?"取消筛选(YOLO)":"只看YOLO"}}
              </n-button>
            </n-flex>
            <n-flex>
              <n-form-item label="置信度阈值" label-placement="left" style="margin:5px 10px" :show-feedback="false">
                <n-input-number
                    v-model:value="filter.yoloConfidenceThreshold"
                    :min="0"
                    :max="1"
                    :step="0.1"
                />
              </n-form-item>
            </n-flex>
            <n-flex>
              <n-form-item label="目标类型" label-placement="left" style="margin:5px 10px" :show-feedback="false">
                <n-checkbox-group v-model:value="filter.yoloNeed">
                  <n-checkbox v-for="option in yoloNeedOptions" :label="option.label" :value="option.value"/>
                </n-checkbox-group>
              </n-form-item>
            </n-flex>
          </div>
          <div style="width: calc(50% - 1px)">
            <n-flex  style="margin: 5px 10px">
              <n-button
                  size="small"
                  :type="filter.only=='PERSON'?'error':'default'"
                  @click="filter.only=='PERSON'?filter.only='DISABLE':filter.only='PERSON'"
              >
                {{filter.only=='PERSON'?"取消筛选(行人结构化数据)":"只看行人结构化数据"}}
              </n-button>
            </n-flex>
            <n-flex>
              <n-form-item style="margin: 5px 10px" label="性别" label-placement="left" :show-feedback="false">
                <n-radio-group v-model:value="filter.personSex">
                  <n-radio
                    v-for="option in ['Male','Female','DISABLE']"
                    :value="option"
                  >{{option}}</n-radio>
                </n-radio-group>
              </n-form-item>
            </n-flex>
            <n-flex>
              <n-form-item style="margin: 5px 10px" label-placement="left" label="年龄范围" :show-feedback="false">
                <n-checkbox-group v-model:value="filter.personAgeRange">
                  <n-checkbox v-for="option in ['Age18-60','AgeOver60','AgeLess18']" :value="option" :label="option"/>
                </n-checkbox-group>
              </n-form-item>
            </n-flex>
          </div>
        </n-flex>
      </div>
      <n-divider vertical style="margin: 0;height: 100%"/>
      <n-scrollbar style="width: calc(40% - 2px);height: calc(100vh - 65px)">
        <n-card
            @click = "selectFrame(data)"
            v-for="data in filterDetectedLogs"
            content-style="padding: 5px"
            style="margin: 5px;width: calc(100% - 10px);"
        >
          <n-flex>
            <n-text>
              {{ showtime(data.timestamp) }}
            </n-text>
          </n-flex>
          <n-flex>
            yolo:
              <n-tag
                  type="success"
                  v-for="(val,key) in sumYoloRes(data.yoloLog)"
              >{{key}}:{{val}}</n-tag>

          </n-flex>
          <n-flex v-if="data.timestamp!=nowDisplayFrame">
              人员特征提取详情数：{{data.personDetail.length}}
          </n-flex>
          <n-scrollbar style="max-height: 200px" v-else>
                <n-card
                    v-for="(person,index) in data.personDetail"
                    content-style="padding: 5px"
                    style="margin: 5px;width: calc(100% - 10px);"
                >
                    <n-text>#{{index+1}}</n-text>
                    <n-descriptions size="small" label-placement="left">
                      <n-descriptions-item label="性别">
                        {{person.sex}}
                      </n-descriptions-item>
                      <n-descriptions-item label="年龄">
                        {{person.ageRange}}
                      </n-descriptions-item>
                      <n-descriptions-item label="帽子">
                        {{person.hasHat?"是":"否"}}
                      </n-descriptions-item>
                      <n-descriptions-item label="眼镜">
                        {{person.hasGlass?"是":"否"}}
                      </n-descriptions-item>
                      <n-descriptions-item label="手包">
                        {{person.hasHandBag?"是":"否"}}
                      </n-descriptions-item>
                      <n-descriptions-item label="手提包">
                        {{person.hasShoulderBag?"是":"否"}}
                      </n-descriptions-item>
                      <n-descriptions-item label="背包">
                        {{person.hasBackPack?"是":"否"}}
                      </n-descriptions-item>
                      <n-descriptions-item label="上身">
                        <n-text :style="coverColor(person.upperColor)">
                          ■
                        </n-text>
                        {{person.upperWear}}
                      </n-descriptions-item>
                      <n-descriptions-item label="下身">
                        <n-text :style="coverColor(person.lowerColor)">
                          ■
                        </n-text>
                        {{person.lowerWear}}
                      </n-descriptions-item>
                    </n-descriptions>
                </n-card>
            </n-scrollbar>
          </n-card>
      </n-scrollbar>
    </n-flex>
  </div>
</template>

<style scoped>

</style>
